package com.ddch.udpsocket.socket.tcp;

import android.content.Context;

import com.ddch.udpsocket.common.Config;
import com.ddch.udpsocket.listener.OnConnectionStateListener;
import com.ddch.udpsocket.util.HeartBeatTimer;
import com.ddch.udpsocket.util.Util;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * created by 韦敏敏
 * on 2019/12/19
 */
public class TCPSocket {
    private Context mContext;
    private ExecutorService mThreadPool;
    private Socket mSocket;
    private BufferedReader br;
    private PrintWriter pw;
    private HeartBeatTimer timer;
    private long lastReceiveTime = 0;
    private OnConnectionStateListener mListener;
    private static final long TIME_OUT = 15 * 1000;
    private static final long HEARTBEAT_MESSAGE_DURATION = 2 * 1000;

    public TCPSocket(Context context) {
        this.mContext = context;
        int cpuNumbers = Runtime.getRuntime().availableProcessors();
        //根据CPU数目初始化线程池
        mThreadPool = Executors.newFixedThreadPool(cpuNumbers * Config.POOL_SIZE);
        // 记录创建对象时的时间
        lastReceiveTime = System.currentTimeMillis();
    }
    public void startTcpSocket(final String ip, final String port){
        mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                // 尝试建立TCP连接
                if(startTcpConnection(ip, Integer.valueOf(port))){
                    if(mListener != null){
                        mListener.onSuccess();
                    }
                    startReceiveTcpThread();
                    startHeartbeatTimer();
                } else {
                    if(mListener != null){
                        mListener.onFailed(Config.ErrorCode.CREATE_TCP_ERROR);
                    }
                }
            }
        });

    }

    /**
     * 创建连接线程
     */
    private void startReceiveTcpThread() {
        mThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                String line = "";
                try {
                    while((line = br.readLine()) != null){
                        handleReceiveTcpMessage(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     *  尝试建立TCP连接
     * @param ip
     * @param port
     * @return
     */
    private boolean startTcpConnection(final String ip, final int port) {
        try {
            if (mSocket == null) {
                mSocket = new Socket(ip, port);
                mSocket.setKeepAlive(true);
                mSocket.setTcpNoDelay(true);
                mSocket.setReuseAddress(true);
            }
            InputStream is = mSocket.getInputStream();
            br = new BufferedReader(new InputStreamReader(is));
            OutputStream os = mSocket.getOutputStream();
            pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os)), true);
            Util.log("tcp 创建成功...");
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     *  关闭Tcp连接
     */
    public void stopTcpConnection(){
        stopHeartbeatTimer();
        try {
            if(br != null)
                br.close();
            if(pw != null)
                pw.close();
            if(mThreadPool != null) {
                mThreadPool.shutdown();
                mThreadPool = null;
            }
            if(mSocket != null){
                mSocket.close();
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void stopHeartbeatTimer() {
        if(timer != null){
            timer.exit();
            timer = null;
        }
    }
    private void startHeartbeatTimer(){
        if(timer == null)
            timer = new HeartBeatTimer();
        timer.setOnScheduleListener(new HeartBeatTimer.OnScheduleListener() {
            @Override
            public void onSchedule() {
                Util.log("timer is onSchedule...");
                long duration = System.currentTimeMillis() - lastReceiveTime;
                Util.log("duration: " + duration);
                // 若超过十五秒都没收到我的心跳包，则认为对方不在线
                if(duration > TIME_OUT){
                    Util.log("tcp ping 超时，对方已经下线");
                    stopTcpConnection();
                    if(mListener != null){
                        mListener.onFailed(Config.ErrorCode.PING_TCP_TIMEOUT);
                    }
                    //若超过两秒他没有收到我的心跳包，则重新发送一个
                } else if(duration > HEARTBEAT_MESSAGE_DURATION){
                    JSONObject jsonObject = new JSONObject();
                    try {
                        jsonObject.put(Config.MSG, Config.PING);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    sendTcpMessage(jsonObject.toString());
                }
            }
        });
        timer.startTimer(0, 1000 * 2);
    }

    /**
     * 发送Tcp消息
     * @param json
     */
    private void sendTcpMessage(String json) {
        pw.println(json);
        Util.log("tcp 消息发送成功...");
    }

    /**
     * 处理Tcp收到的消息
     * @param line
     */
    private void handleReceiveTcpMessage(String line){
        Util.log("接收tcp消息: " + line);
        lastReceiveTime = System.currentTimeMillis();
    }
    // 设置连接状态监听器
    public void setOnConnectionStateListener(OnConnectionStateListener listener){
        this.mListener = listener;
    }
}
